package org.sam.swing.table.matrixImpl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.event.TableModelEvent;

import org.apache.commons.lang3.tuple.Pair;
import org.sam.swing.table.JSTableColumn;
import org.sam.swing.table.JSTableModel;
import org.sam.swing.table.JSTableModelLinster;
import org.sam.swing.table.verification.Verification;
import org.sam.swing.utils.ReflectUtil;

/**
 * 交叉表格talbeModel对象 目前只实现修改功能
 * 
 * @author sam
 *
 * @param <T>
 */
public class JSTableMatrixModel<G, T> extends JSTableModel<Map<G, List<T>>> {

	private static final long serialVersionUID = 5778752367658910723L;

	/**
	 * 原始的值
	 */
	private volatile Map<G, List<T>> orginal;

	/**
	 * 要更新的集合列表
	 */
	private List<T> modifies = new LinkedList<>();

	/**
	 * {@inheritDoc}
	 * 
	 * @return
	 */
	@Override
	public JSTableModelLinster<Map<G, List<T>>> getTableModelLinster() {
		
		if (super.getTableModelLinster() == null)
			this.setTableModelLinster(new JSTableModelMatrixAdapter<G, T>());
		return super.getTableModelLinster();
	}

	/**
	 * 获取横向展开列
	 * 
	 * @return
	 */
	protected JSTableMatrixHColumn getHColumn() throws Exception {
		JSTableColumn[] columns = this.getOrginalColumn();
		if (columns == null || columns.length <= 0)
			throw new Exception("no enough columns");

		for (JSTableColumn colmn : columns) {
			if (colmn instanceof JSTableMatrixHColumn) {
				return (JSTableMatrixHColumn) colmn;
			}
		}

		throw new Exception("matrix table must have a JSTableMatrixHColumn object");
	}

	/**
	 * 获取纵向展开列
	 * 
	 * @return
	 */
	protected JSTableMatrixVColumn getVColumn() throws Exception {
		JSTableColumn[] columns = this.getOrginalColumn();
		if (columns == null || columns.length <= 0)
			throw new Exception("no enough columns");

		for (JSTableColumn colmn : columns) {
			if (colmn instanceof JSTableMatrixVColumn) {
				return (JSTableMatrixVColumn) colmn;
			}
		}

		throw new Exception("matrix table must have a JSTableMatrixVSColumn object");
	}

	/**
	 * 获取值列
	 * 
	 * @return
	 * @throws Exception
	 */
	protected JSTableMatrixValueColumn getValueColumn() throws Exception {
		JSTableColumn[] columns = this.getOrginalColumn();
		if (columns == null || columns.length <= 0)
			throw new Exception("no enough columns");

		for (JSTableColumn colmn : columns) {
			if (colmn instanceof JSTableMatrixValueColumn) {
				return (JSTableMatrixValueColumn) colmn;
			}
		}

		throw new Exception("matrix table must have a JSTableMatrixValueColumn object");
	}

	/**
	 * 缓存起来的已经扩容过的matrix列数据
	 */
	private JSTableColumn[] matrixedColumn;
	
	/**
	 * 原始的column集合对象
	 */
	private JSTableColumn[] orginalColumn;
	
	/**
	 * 原始状态的列对象
	 * @return
	 */
	public JSTableColumn[] getOrginalColumn() {
		if (orginalColumn == null){
			orginalColumn = this.getTableColumns();
		}
		return orginalColumn;
	}

	/**
	 * + 获取重新生成的矩阵列
	 * 
	 * @return
	 * @throws Exception
	 */
	public JSTableColumn[] getMatrixColumns() throws Exception {
		if (this.orginal == null || this.orginal.isEmpty()){
			return this.getOrginalColumn();
		}

		if (matrixedColumn != null && matrixedColumn.length > 0)
			return matrixedColumn;

		this.setMatrixColumns();
		return matrixedColumn;
	}
	
	/**
	 * 重新根据用户设置的columns生成新的数据
	 * 
	 * @throws Exception
	 */
	public void setMatrixColumns() throws Exception {
		JSTableColumn[] columns = this.getOrginalColumn();
		if (columns == null || columns.length <= 0)
			throw new Exception("no enough columns");

		// 重新扩展列
		// 简易版实现：从数据的第一行拿到，重新生成column
		// 未来完整版：从所有数据里取不重复的，重新生成column
		if (this.orginal == null || this.orginal.isEmpty())
			throw new Exception("");

		Collection<T> values = this.orginal.values().iterator().next();
		List<JSTableColumn> cols = new LinkedList<>();
		int i = 0; // 重新生成modelindex
		int j = 0; // 生成横向扩展数据索引位置

		JSTableMatrixValueColumn valueColumn = this.getValueColumn();

		for (JSTableColumn colmn : columns) {
			if (colmn instanceof JSTableMatrixHColumn) {
				// 横向扩展列
				for (T t : values) {
					JSTableMatrixHColumn cloneColumn = (JSTableMatrixHColumn) ((JSTableMatrixHColumn) colmn).clone();
					// 拿到表头对应的值，然后赋值给新列的表头
					Pair<Boolean, Object> invokeResult = ReflectUtil.invokeGetMethod(t,
							cloneColumn.getIdentifier().toString());
					cloneColumn.setIdentifier(valueColumn.getIdentifier());
					if (invokeResult.getKey()) {
						cloneColumn.setHeaderValue(invokeResult.getValue());
					}
					cloneColumn.setDefaultValue(valueColumn.getDefaultValue());
					cloneColumn.setCellRenderer(valueColumn.getCellRenderer());
					cloneColumn.setCellEditor(valueColumn.getCellEditor());
					cloneColumn.setModelIndex(i++);
					cloneColumn.setIndex(j++);
					cols.add(cloneColumn);
				}
			} else if (colmn instanceof JSTableMatrixVColumn) {
				// 纵向扩展列，不需要变化
				colmn.setModelIndex(i++);
				cols.add(colmn);
			} else if (colmn instanceof JSTableMatrixValueColumn) {
				// 值列
				// 不操做，因为横向扩展列已经包含这个信息了
			} else {
				colmn.setModelIndex(i++);
				cols.add(colmn);
			}
		}

		this.matrixedColumn = cols.toArray(new JSTableColumn[cols.size()]);
		//重新生成表头
		this.setColumnIdentifiers(this.matrixedColumn);
	}

	/**
	 * 更新表格的操作
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void tableChanged(TableModelEvent e) {
		// insert 是直接在 tablemodel插入数据的，所以我觉得不用单独在时间里操作了
		if (e.getType() == TableModelEvent.INSERT) {
		} else if (e.getType() == TableModelEvent.UPDATE) {
			try {
				this.removeTableModelListener(this);
				int iRow = e.getFirstRow();

				int findColumn = this.findColumn(JSTableColumn.COLUMN_ORIGINAL);
				if (findColumn < 0)
					throw new Exception("get orignal data column fail");

				List<T> datas = (List<T>) this.getValueAt(iRow, findColumn);
				if (datas == null)
					throw new Exception("get orignal data fail");

				String colName = this.getColumnName(e.getColumn());
				if (colName == null || colName.length() <= 0)
					return;

				if (JSTableColumn.COLUMN_ORIGINAL.equals(colName)) {
					return;
				}

				// matrix的一般是横列，纵向列，值，隐藏原始值这些列，原始值列是一整行的原始数据对象
				// 每个单元格编辑就是编辑一个实体对象
				// 目前矩阵对象暂时不实现删除，插入操作。所以只实现了一个简版的编辑功能的表格
				// 目前只处理横向扩展列
				JSTableColumn col = this.getMatrixColumns()[e.getColumn()];
				if (col instanceof JSTableMatrixHColumn) {
					JSTableMatrixHColumn c = (JSTableMatrixHColumn) col;
					T t = datas.get(c.getIndex());
					Method setMethod = ReflectUtil.getSetMethod(t, colName);
					setMethod.invoke(t, this.getValueAt(e.getFirstRow(), e.getColumn()));
					datas.set(c.getIndex(), t);
					if (this.modifies.contains(t)) {
						// 如果是在更新组里的话
					} else {
						this.modifies.add(t);
					}
					// 以下这句会引起连锁反应，比如在窗口上更新了一个数据，然后会重新激发本事件代码，但是列变成了col_orginal
					this.setValueAt(datas, iRow, findColumn);
				}

			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				this.addTableModelListener(this);
			}
		} else if (e.getType() == TableModelEvent.DELETE) {
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<G, List<T>> getOrginal() {
		return orginal;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setOrginal(Map<G, List<T>> orginal) {
		this.orginal = orginal;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<G, List<T>> getDeletes() {
		return new HashMap<>();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setDeletes(Map<G, List<T>> deletes) {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<G, List<T>> getCreates() {
		return new HashMap<>();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setCreates(Map<G, List<T>> creates) {

	}

	/**
	 * 包装一个空的修改类型
	 */
	@Override
	public Map<G, List<T>> getModified() {
		Map<G, List<T>> result = new HashMap<>();
		result.put(null, this.modifies);
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setModified(Map<G, List<T>> modified) {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void resetUpdate() {
		this.modifies.clear();
	}

	/**
	 * 交叉表格检索数据的操作
	 */
	@Override
	public int onRetrieve() throws Exception {
		try {

			orginal = this.getTableModelLinster().onRetrieve();
			/**
			 * 如果设置为插入空白行，则新增加的时候，直接插入一行空白
			 */
			if (this.isRetrieveWithEmptyRow()) {
				Object[] createNew = this.createNew();
				int findColumn = this.findColumn(JSTableColumn.COLUMN_ORIGINAL);
				createNew[findColumn] = null;
				addRow(createNew);
			}

			JSTableColumn[] cols = this.getMatrixColumns();
			if (orginal != null && !orginal.isEmpty()) {
				for (Entry<G, List<T>> entry : orginal.entrySet()) {
					// 假设已经生成完成了列的映射，然后根据列绑定的次序我们插入数据
					// 数据集合
					Object[] datas = new Object[getColumnCount()];
					for (int i = 0; i < getColumnCount(); i++) {
						String colName = getColumnName(i);
						if (JSTableColumn.COLUMN_ORIGINAL.equals(colName)) {
							datas[i] = entry.getValue();
						} else {
							if (null == colName || colName.length() <= 0) {
								datas[i] = cols[i].getDefaultValue();
							} else {

								if (cols[i] instanceof JSTableMatrixHColumn) {
									// 横向扩展列
									JSTableMatrixHColumn c = (JSTableMatrixHColumn) cols[i];
									T t = entry.getValue().get(c.getIndex());
									Pair<Boolean, Object> invokeResult = ReflectUtil.invokeGetMethod(t,
											c.getIdentifier().toString());

									if (invokeResult.getKey()) {
										datas[i] = invokeResult.getValue();
									} else {
										Field field = t.getClass().getDeclaredField(colName);
										if (field == null)
											continue;
										field.setAccessible(true);
										datas[i] = field.get(t);
									}
								} else if (cols[i] instanceof JSTableMatrixVColumn) {
									// 纵向扩展列，不需要变化
									datas[i] = entry.getKey();
								} else {

								}
							}
						}
					}
					addRow(datas);
				}

				return orginal.size();
			}

		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
		return 0;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onDelete(int moduleRow) throws Exception {
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onInsert(int moduleRow) throws Exception {
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onAppend() throws Exception {
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean hasChange() {
		return this.modifies.size() > 0;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void moveRow(int srcRow, int tarRow) throws Exception {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Map<G, List<T>> getDatas() throws Exception {
		return this.orginal;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void reBuildIndex(int colIndex, int begin, int seed) throws Exception {

	}

	@Override
	public Object getData(int modelRow) throws Exception {
		int iOriginal = this.findColumn(JSTableColumn.COLUMN_ORIGINAL);
		if (iOriginal < 0)
			throw new Exception("Not include original data");

		if (modelRow < 0 || modelRow >= this.getRowCount())
			throw new Exception("modelRow over index");

		return this.getValueAt(modelRow, iOriginal);
	}

	/**
	 * 生成一行空数据 使用defualt生成数据
	 */
	@Override
	public Object[] createNew() throws Exception {

		JSTableColumn[] cols = this.getMatrixColumns();
		Object[] datas = new Object[cols.length];

		// 未找到绑定的实体列
		int originalCol = this.findColumn(JSTableColumn.COLUMN_ORIGINAL);
		if (originalCol < 0)
			throw new Exception("not init the original column");

		// 初始化数据
		for (int i = 0; i < cols.length; i++) {
			JSTableColumn column = cols[i];
			String colName = column.getIdentifier().toString();

			// 无数据绑定列
			if (null == colName || colName.length() <= 0) {

			} else if (originalCol == i) {
				datas[i] = new LinkedList<>();
			} else {
				datas[i] = column.getDefaultValue();
			}
		}
		return datas;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void clear() throws Exception {
		for (int i = this.getRowCount() - 1; i >= 0; i--) {
			this.removeRow(i);
		}

		this.resetUpdate();

		if (this.orginal != null)
			this.orginal = null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insert(int row, Object t) throws Exception {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void replace(int row, Object t) throws Exception {

	}

	@Override
	public boolean isUseClientVerification() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void setUseClientVerification(boolean used) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Verification getVerification() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setVerification(Verification verification) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isTableColumnVerificatior() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void setTableColumnVerificatior(boolean verificat) {
		// TODO Auto-generated method stub
		
	}

}
